{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SB93Ge748VQs"
      },
      "source": [
        "##### Copyright 2019 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "0sK8X2O9bTlz"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HEYuO5NFwDK9"
      },
      "source": [
        "# tf.summary の使用箇所を TF 2.0 に移行する\n",
        "\n",
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td><a target=\"_blank\" href=\"https://www.tensorflow.org/tensorboard/migrate\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\">TensorFlow.org で表示</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ja/tensorboard/migrate.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\">Google Colab で実行</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ja/tensorboard/migrate.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\">GitHub でソースを表示</a></td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "56V5oun18ZdZ"
      },
      "source": [
        "> 注意: このドキュメントは、TensorFlow 1.x TensorBoard に精通している方で大規模な TensorFlow コードベースを TensorFlow 1.x から 2.0 に移行したい方を対象としています。TensorBoard にまだ新しい方は、[基礎](get_started.ipynb)ドキュメントをご覧ください。`tf.keras` を使用している場合は、TensorFlow 2.0 にアップグレードするための作業が必要ない場合があります。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "c50hsFk2MiWs"
      },
      "outputs": [],
      "source": [
        "import tensorflow as tf"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "56XvRdPy-ewT"
      },
      "source": [
        "TensorFlow 2.0 では、TensorBoard での視覚化に使用する要約データを書き込む際の `tf.summary` API が大幅に変更されています。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "V_JOBTVzU5Cx"
      },
      "source": [
        "## 変更点\n",
        "\n",
        "`tf.summary` API を 2 つのサブ API として考えると良いでしょう。\n",
        "\n",
        "- 個別の要約を記録するための一連の演算 - `summary.scalar()`、`summary.histogram()`、`summary.image()`、`summary.audio()`、および `summary.text()`。これらはモデルコードからインラインで呼び出されます。\n",
        "- 上記の個別の要約を収集して特別にフォーマットされたログファイル（TensorBoard が読み取って視覚化を生成するファイル）に書き込む書き込みロジック。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9-rVv-EYU8_E"
      },
      "source": [
        "### TF 1.x の場合\n",
        "\n",
        "上記の 2 つは、`Session.run()` でサマリー演算の出力をフェッチし、`FileWriter.add_summary(output, step)` で呼び出す、というように手動でつなぐ必要がありました。`v1.summary.merge_all()` 演算によって、グラフコレクションを使ってすべてのサマリー演算出力を集計するという方法で、この処理が簡単になっていますが、Eager execution と制御フローではあまりよく機能しなかったため、TF 2.0 には特に適していません。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rh8R2g5FWbsQ"
      },
      "source": [
        "### TF 2.X の場合\n",
        "\n",
        "上記の 2 つは密接に統合されており、個別の `tf.summary` 演算は実行時に直ちにデータを書き込むようになっています。モデルコードから API を使用する方法はあまり変わっていませんが、Eager execution との相性が改善されており、ほかのグラフモードとの互換性もそのままです。この 2 つの API を統合することで、`summary.FileWriter` は TensorFlow 実行コンテキストの一環となり、`tf.summary` 演算で直接アクセスできるため、ライターの構成が外見的な主な違いと言えます。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "em7GQju5VA0I"
      },
      "source": [
        "次は、TF 2.0 のデフォルトのモードである Eager execution を使用した例です。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "GgFXOtSeVFqP"
      },
      "outputs": [],
      "source": [
        "writer = tf.summary.create_file_writer(\"/tmp/mylogs/eager\")\n",
        "\n",
        "with writer.as_default():\n",
        "  for step in range(100):\n",
        "    # other model code would go here\n",
        "    tf.summary.scalar(\"my_metric\", 0.5, step=step)\n",
        "    writer.flush()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "h5fk_NG7QKve"
      },
      "outputs": [],
      "source": [
        "ls /tmp/mylogs/eager"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FvBBeFxZVLzW"
      },
      "source": [
        "次は、tf.function グラフ実行の使用例です。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "kovK0LEEVKjR"
      },
      "outputs": [],
      "source": [
        "writer = tf.summary.create_file_writer(\"/tmp/mylogs/tf_function\")\n",
        "\n",
        "@tf.function\n",
        "def my_func(step):\n",
        "  with writer.as_default():\n",
        "    # other model code would go here\n",
        "    tf.summary.scalar(\"my_metric\", 0.5, step=step)\n",
        "\n",
        "for step in tf.range(100, dtype=tf.int64):\n",
        "  my_func(step)\n",
        "  writer.flush()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Qw5nHhRUSM7_"
      },
      "outputs": [],
      "source": [
        "ls /tmp/mylogs/tf_function"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "5SY6eYitUJH_"
      },
      "source": [
        "次は、レガシー TF 1.x グラフ実行の使用例です。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "OyQgeqZhVRNB"
      },
      "outputs": [],
      "source": [
        "g = tf.compat.v1.Graph()\n",
        "with g.as_default():\n",
        "  step = tf.Variable(0, dtype=tf.int64)\n",
        "  step_update = step.assign_add(1)\n",
        "  writer = tf.summary.create_file_writer(\"/tmp/mylogs/session\")\n",
        "  with writer.as_default():\n",
        "    tf.summary.scalar(\"my_metric\", 0.5, step=step)\n",
        "  all_summary_ops = tf.compat.v1.summary.all_v2_summary_ops()\n",
        "  writer_flush = writer.flush()\n",
        "\n",
        "\n",
        "with tf.compat.v1.Session(graph=g) as sess:\n",
        "  sess.run([writer.init(), step.initializer])\n",
        "\n",
        "  for i in range(100):\n",
        "    sess.run(all_summary_ops)\n",
        "    sess.run(step_update)\n",
        "    sess.run(writer_flush)  "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "iqKOyawnNQSH"
      },
      "outputs": [],
      "source": [
        "ls /tmp/mylogs/session"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xEJIh4btVVRb"
      },
      "source": [
        "## コードを変換する\n",
        "\n",
        "既存の `tf.summary` の使用箇所を TF 2.0 API に変換する作業は、確実に自動化することはできないため、[`tf_upgrade_v2` スクリプト](https://www.tensorflow.org/guide/upgrade)は、すべてを `tf.compat.v1.summary` に書き換えることしか行いません。TF 2.0 に移行するには、コードを次のように適応させる必要があります。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Pq4Fy1bSUdrZ"
      },
      "source": [
        "1. サマリー演算を使用するには、`.as_default()` によるデフォルトのライターセットが存在する必要がある\n",
        "\n",
        "    - つまり、演算を Eager で実行するか、グラフ構造で演算を使用する\n",
        "    - デフォルトのライターがない場合、サマリー演算はサイレントの no-op になる\n",
        "    - デフォルトのライターは（まだ）`@tf.function` 実行境界に伝搬しません。関数がトレースされた場合にのみ検出されるため、関数の本文で `writer.as_default()` を呼び出し、`@tf.function` が使用される限りライターオブジェクトが存在し続けられるようにすることが、ベストプラクティスと言えます。\n",
        "\n",
        "2. 「step」値は `step` 引数で各演算に渡される必要がある\n",
        "\n",
        "    - TensorBoard には、時系列としてデータをレンダリングするステップ値が必要です\n",
        "    - TF 1.x のグローバルステップは削除されており、各演算は読み取るための希望する step 変数を知っておくために、明示的に渡す必要があります\n",
        "    - ボイラープレートを減らすために、デフォルトステップを登録するための実験的サポートは`tf.summary.experimental.set_step()` として提供されていますが、これは暫定機能であり、予告なく変更される場合があります\n",
        "\n",
        "3. 個々のサマリー演算の関数シグネチャが変更されている\n",
        "\n",
        "    - 戻り値はブール型になっています（要約が実際に書き込まれたかどうかを示す）\n",
        "    - 2 番目のパラメータ名（使用される場合）が`tensor` から `data` に代わっています\n",
        "    - `collections` パラメータが削除されています。collections は TF 1.x のみのパラメータです\n",
        "    - `family` パラメータが削除されています。`tf.name_scope()` を使用してください\n",
        "\n",
        "4. ［レガシーグラフモードのみ / セッション実行ユーザー］\n",
        "\n",
        "    - 最初に `v1.Session.run(writer.init())` でライターを初期化します\n",
        "\n",
        "    - `v1.summary.all_v2_summary_ops()` を使用して、現在のグラフに関するすべての TF 2.0 サマリー演算を取得します（`Session.run()` で実行するためなど）。\n",
        "\n",
        "    - `v1.Session.run(writer.flush())` でライターをフラッシュし、`close()` でも同様にフラッシュします\n",
        "\n",
        "TF 1.x コードで `tf.contrib.summary` API を使用していた場合は、TF 2.0 API にはるかに似ているため、`tf_upgrade_v2` スクリプトを使って、ほとんどの移行ステップ（および完全に移行できない使用箇所の発行警告またはエラー）を自動化できます。ほとんどにおいて、API 呼び出しを `tf.compat.v2.summary` に書き直すだけであるため、TF 2.0+ との互換性のみが必要である場合は、`compat.v2` を削除して、`tf.summary` として参照するようにすることができます。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1GUZRWSkW3ZC"
      },
      "source": [
        "## その他のヒント\n",
        "\n",
        "上記の重要な分野に加え、一部の補助的な側面も変更されています。\n",
        "\n",
        "- 条件付き記録（「100 ステップごとにログ」など）が新しくなりました\n",
        "\n",
        "    - 演算と関連するコードを制御するには、通常の if ステートメント（Eager モードと[自動グラフ作成経由の `@tf.function`](https://www.tensorflow.org/alpha/guide/autograph) で機能）か、`tf.cond` でラップします\n",
        "    - 要約のみを制御するには、新しい `tf.summary.record_if()` コンテキストマネージャを使用して、選択したブール条件を渡します\n",
        "    - TF 1.x パターンを置き換えます\n",
        "        ```\n",
        "        if condition:   writer.add_summary()\n",
        "        ```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9VMYrKn4Uh52"
      },
      "source": [
        "- `tf.compat.v1.Graph` を直接書き込めない代わりにトレース関数を使用します\n",
        "\n",
        "    - TF 2.0 のグラフ実行では、明示的な Graph の代わりに `@tf.function` が使用されます\n",
        "    - TF 2.0 では、新しいトレース式 API である`tf.summary.trace_on()` と `tf.summary.trace_export()` を使用して、実行した関数グラフを記録します\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "UGItA6U0UkDx"
      },
      "source": [
        "- `tf.summary.FileWriterCache` の使用により、logdir ごとのグローバルライターのキャッシュが不要になります\n",
        "\n",
        "    - ユーザーは、ライターオブジェクトの独自のキャッシュ/共有を実装するか、個別のライターを使用する必要があります（TensorBoard の後者のサポートは[開発中](https://github.com/tensorflow/tensorboard/issues/1063)です）\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "d7BQJVcsUnMp"
      },
      "source": [
        "- イベントファイルのバイナリ表現が変更されました\n",
        "\n",
        "    - TensorBoard 1.x は、新しい形式をサポート済みです。この違いは、要約データをイベントファイルから手動で解析しているユーザーのみに影響します）\n",
        "    - 要約データはテンソルバイトとして保存されるようになりました。`tf.make_ndarray(event.summary.value[0].tensor)` を使って numpy に変換できます。"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "name": "migrate.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
